home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 8: LINUX Games / Linux Cubed Series 8 - LINUX Games.iso / games / x11 / rpg / crossfir.92 / crossfir / crossfire-0.92.5 / server / main.c < prev    next >
C/C++ Source or Header  |  1996-07-24  |  26KB  |  873 lines

  1. /*
  2.  * static char *rcsid_main_c =
  3.  *    "$Id: main.c,v 1.36 1996/01/02 11:44:23 master Exp $";
  4.  */
  5.  
  6. /*
  7.     CrossFire, A Multiplayer game for X-windows
  8.  
  9.     Copyright (C) 1994 Mark Wedel
  10.     Copyright (C) 1992 Frank Tore Johansen
  11.  
  12.     This program is free software; you can redistribute it and/or modify
  13.     it under the terms of the GNU General Public License as published by
  14.     the Free Software Foundation; either version 2 of the License, or
  15.     (at your option) any later version.
  16.  
  17.     This program is distributed in the hope that it will be useful,
  18.     but WITHOUT ANY WARRANTY; without even the implied warranty of
  19.     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  20.     GNU General Public License for more details.
  21.  
  22.     You should have received a copy of the GNU General Public License
  23.     along with this program; if not, write to the Free Software
  24.     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  25.  
  26.     The author can be reached via e-mail to master@rahul.net
  27. */
  28.  
  29. #if ((defined(__sun__) || defined(__sgi)) && defined(SVR4))
  30. #include <crypt.h>
  31. #endif
  32. #if defined(__osf__)
  33. /* <crypt.h> declares crypt_r(), but not crypt() !?! (OSF/1 1.0) */
  34. extern char *crypt(const char *, const char *);
  35. #endif
  36.  
  37. #include <version.h>
  38. #include <global.h>
  39. #ifndef __CEXTRACT__
  40. #include <sproto.h>
  41. #endif
  42. #include <main.h>
  43. #include <object.h>
  44. #if defined (_IBMR2) || defined (___IBMR2) /* Which is correct? */
  45. #include <time.h>
  46. #endif
  47.  
  48. static char days[7][4] = {
  49.   "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"};
  50.  
  51. void version(object *op) {
  52.   if(op!=NULL)
  53.     clear_win_info(op);
  54.  
  55.   new_draw_info_format(NDI_UNIQUE, 0, op, "This is Crossfire v%s%s",VERSION,PATCH);
  56.  
  57. /* If in a socket, don't print out the list of authors.  It confuses the
  58.  * crossclient program.
  59.  */
  60.   if (op==NULL) return;
  61.   new_draw_info(NDI_UNIQUE, 0,op,"Authors and contributors to this program:");
  62.   new_draw_info(NDI_UNIQUE, 0,op,"master@rahul.net (Mark Wedel)");
  63.   new_draw_info(NDI_UNIQUE, 0,op,"frankj@ifi.uio.no (Frank Tore Johansen)");
  64.   new_draw_info(NDI_UNIQUE, 0,op,"kjetilho@ifi.uio.no (Kjetil Torgrim Homme)");
  65.   new_draw_info(NDI_UNIQUE, 0,op,"tvangod@ecst.csuchico.edu (Tyler Van Gorder)");
  66.   new_draw_info(NDI_UNIQUE, 0,op,"elmroth@cd.chalmers.se (Tony Elmroth)");
  67.   new_draw_info(NDI_UNIQUE, 0,op,"dougal.scott@fcit.monasu.edu.au (Dougal Scott)");
  68.   new_draw_info(NDI_UNIQUE, 0,op,"wchuang@athena.mit.edu (William)");
  69.   new_draw_info(NDI_UNIQUE, 0,op,"ftww@cs.su.oz.au (Geoff Bailey)");
  70.   new_draw_info(NDI_UNIQUE, 0,op,"jorgens@flipper.pvv.unit.no (Kjetil Wiekhorst Jxrgensen)");
  71.   new_draw_info(NDI_UNIQUE, 0,op,"c.blackwood@rdt.monash.edu.au (Cameron Blackwood)");
  72.   new_draw_info(NDI_UNIQUE, 0,op,"jtraub+@cmu.edu (Joseph L. Traub)");
  73.   new_draw_info(NDI_UNIQUE, 0,op,"rgg@aaii.oz.au (Rupert G. Goldie)");
  74.   new_draw_info(NDI_UNIQUE, 0,op,"eanders+@cmu.edu (Eric A. Anderson)");
  75.   new_draw_info(NDI_UNIQUE, 0,op,"eneq@Prag.DoCS.UU.SE (Rickard Eneqvist)");
  76.   new_draw_info(NDI_UNIQUE, 0,op,"Jarkko.Sonninen@lut.fi (Jarkko Sonninen)");
  77.   new_draw_info(NDI_UNIQUE, 0,op,"kholland@sunlab.cit.cornell.du (Karl Holland)");
  78.   new_draw_info(NDI_UNIQUE, 0,op,"vick@bern.docs.uu.se (Mikael Lundgren)");
  79.   new_draw_info(NDI_UNIQUE, 0,op,"mol@meryl.csd.uu.se (Mikael Olsson)");
  80.   new_draw_info(NDI_UNIQUE, 0,op,"Tero.Haatanen@lut.fi (Tero Haatanen)");
  81.   new_draw_info(NDI_UNIQUE, 0,op,"ylitalo@student.docs.uu.se (Lasse Ylitalo)");
  82.   new_draw_info(NDI_UNIQUE, 0,op,"anipa@guru.magic.fi (Niilo Neuvo)");
  83.   new_draw_info(NDI_UNIQUE, 0,op,"mta@modeemi.cs.tut.fi (Markku J{rvinen)");
  84.   new_draw_info(NDI_UNIQUE, 0,op,"meunier@inf.enst.fr (Sylvain Meunier)");
  85.   new_draw_info(NDI_UNIQUE, 0,op,"jfosback@darmok.uoregon.edu (Jason Fosback)");
  86.   new_draw_info(NDI_UNIQUE, 0,op,"cedman@capitalist.princeton.edu (Carl Edman)");
  87.   new_draw_info(NDI_UNIQUE, 0,op,"henrich@crh.cl.msu.edu (Charles Henrich)");
  88.   new_draw_info(NDI_UNIQUE, 0,op,"schmid@fb3-s7.math.tu-berlin.de (Gregor Schmid)");
  89.   new_draw_info(NDI_UNIQUE, 0,op,"quinet@montefiore.ulg.ac.be (Raphael Quinet)");
  90.   new_draw_info(NDI_UNIQUE, 0,op,"jam@modeemi.cs.tut.fi (Jari Vanhala)");
  91.   new_draw_info(NDI_UNIQUE, 0,op,"kivinen@joker.cs.hut.fi (Tero Kivinen)");
  92.   new_draw_info(NDI_UNIQUE, 0,op,"peterm@soda.berkeley.edu (Peter Mardahl)");
  93.   new_draw_info(NDI_UNIQUE, 0,op,"matt@cs.odu.edu (Matthew Zeher)");
  94.   new_draw_info(NDI_UNIQUE, 0,op,"srt@sun-dimas.aero.org (Scott R. Turner)");
  95.   new_draw_info(NDI_UNIQUE, 0,op,"huma@netcom.com (Ben Fennema)");
  96.   new_draw_info(NDI_UNIQUE, 0,op,"njw@cs.city.ac.uk (Nick Williams)");
  97.   new_draw_info(NDI_UNIQUE, 0,op,"Wacren@Gin.ObsPM.Fr (Laurent Wacrenier)");
  98.   new_draw_info(NDI_UNIQUE, 0,op,"thomas@astro.psu.edu (Brian Thomas)");
  99.   new_draw_info(NDI_UNIQUE, 0,op,"jsm@axon.ksc.nasa.gov (John Steven Moerk)");
  100. }
  101.  
  102. void info_keys(object *op) {
  103.   clear_win_info(op);
  104.   new_draw_info(NDI_UNIQUE, 0,op,"Push `hjklynub' to walk in a direction.");
  105.   new_draw_info(NDI_UNIQUE, 0,op,"Shift + dir = fire, Ctrl + dir = run");
  106.   new_draw_info(NDI_UNIQUE, 0,op,"(To fire at yourself, hit `.'");
  107.   new_draw_info(NDI_UNIQUE, 0,op,"To attack, walk into the monsters.");
  108.   new_draw_info(NDI_UNIQUE, 0,op,"\"  = speak        ' = extended command");
  109.   new_draw_info(NDI_UNIQUE, 0,op,"i  = inventory    , = get         : = look");
  110.   new_draw_info(NDI_UNIQUE, 0,op,"<> = rotate       d = drop        ? = help");
  111.   new_draw_info(NDI_UNIQUE, 0,op,"a  = apply        A = apply below t = throw");
  112.   new_draw_info(NDI_UNIQUE, 0,op,"e  = examine      E = exa below   @ = autopick");
  113.   new_draw_info(NDI_UNIQUE, 0,op,"C  = configure    s = brace       v = version");
  114.   new_draw_info(NDI_UNIQUE, 0,op,"+- = change range <tab> = browse spells");
  115.   new_draw_info(NDI_UNIQUE, 0,op,"x  = change inventory type");
  116. #ifdef SAVE_WINDOW_POSITIONS
  117.   new_draw_info(NDI_UNIQUE, 0,op,"X  = Toggle window position saving.");
  118. #endif /* SAVE_WINDOW_POSITIONS */
  119.   new_draw_info(NDI_UNIQUE, 0,op,"Mouse: L = examine,  M = apply,  R = drop/get");
  120.   new_draw_info(NDI_UNIQUE, 0,op,"'help  = info about extended commands.");
  121.   new_draw_info(NDI_UNIQUE, 0,op,"Ctrl-R = refresh   Ctrl-C = clear");
  122.   new_draw_info(NDI_UNIQUE, 0,op,"You can type a number before most commands.");
  123.   new_draw_info(NDI_UNIQUE, 0,op,"(For instance 3d drops 3 items.)");
  124. }
  125.  
  126. void start_info(object *op) {
  127.   char buf[MAX_BUF];
  128.  
  129.   sprintf(buf,"Welcome to Crossfire, v%s%s!",VERSION,PATCH);
  130.   new_draw_info(NDI_UNIQUE, 0,op,buf);
  131.   new_draw_info(NDI_UNIQUE, 0,op,"Press `?' for help");
  132.   new_draw_info(NDI_UNIQUE, 0,op," ");
  133.   new_draw_info_format(NDI_UNIQUE | NDI_ALL, 5, op,
  134.     "%s entered the game.",op->name);
  135.   if(!op->contr->name_changed) {
  136.     new_draw_info(NDI_UNIQUE, 0,op,"Note that you must set your name with the name");
  137.     new_draw_info(NDI_UNIQUE, 0,op,"command to enter the highscore list.");
  138.     new_draw_info(NDI_UNIQUE, 0,op,"(You can also use the crossfire.name X-resource.)");
  139.   }
  140. }
  141.  
  142. char *crypt_string(char *str, char *salt) {
  143.   static char *c=
  144.     "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789./";
  145.   char s[2];
  146.   if(salt==NULL)
  147.     s[0]= c[RANDOM() % (int)strlen(c)],
  148.     s[1]= c[RANDOM() % (int)strlen(c)];
  149.   else
  150.     s[0]= salt[0],
  151.     s[1]= salt[1];
  152.   return crypt(str,s);
  153. }
  154.  
  155. int check_password(char *typed,char *crypted) {
  156.   return !strcmp(crypt_string(typed,crypted),crypted);
  157. }
  158.  
  159. char *normalize_path (char *src, char *dst) {
  160.     char *p, *q;
  161.     char buf[MAX_BUF];
  162.     static char path[MAX_BUF];
  163.  
  164.     /* LOG(llevDebug,"path before normalization >%s<>%s<\n", src, dst); */
  165.  
  166.     if (*dst == '/') {
  167.     strcpy (buf, dst);
  168.  
  169.     } else {
  170.     strcpy (buf, src);
  171.     if ((p = strrchr (buf, '/')))
  172.         p[1] = '\0';
  173.     else
  174.         strcpy (buf, "/");
  175.     strcat (buf, dst);
  176.     }
  177.  
  178.     q = p = buf;
  179.     while ((q = strstr (q, "//")))
  180.     p = ++q;    
  181.  
  182.     *path = '\0';
  183.     q = path;
  184.     p = strtok (p, "/");
  185.     while (p) {
  186.     if (!strcmp (p, "..")) {
  187.         q = strrchr (path, '/');
  188.         if (q)
  189.         *q = '\0';
  190.         else {
  191.         *path = '\0';
  192.         LOG (llevError, "Illegal path.\n");
  193.         }
  194.     } else {
  195.         strcat (path, "/");
  196.         strcat (path, p);
  197.     }
  198.     p = strtok (NULL, "/");
  199.     }
  200.     /* LOG(llevDebug,"path after normalization >%s<\n", path); */
  201.  
  202.     return (path);
  203. }
  204.  
  205. /* Tries to move 'op' to exit_ob.  op is the character or monster that is
  206.  * using the exit, where exit_ob is the exit object (boat, door, teleporter,
  207.  * etc.)  if exit_ob is null, then op->maplevel contains that map to
  208.  * move the object to (and use default map coordiantes
  209.  */
  210.  
  211. void enter_exit(object *op, object *exit_ob) {
  212.   char buf[MAX_BUF];
  213.  
  214.   /* having dummy_map be non static is better for two reasons - with it
  215.    * being static, only 1 instance of it was created, and thus, if this
  216.    * function was called recursively, dummy_map would not have an
  217.    * expected value.  Second, dummy_map is no longer needed once this
  218.    * function finishes, and as I understand it, its data will be accessible
  219.    * until that time --MSW
  220.    */
  221.   mapstruct *m, dummy_map;
  222.   int x=0, y=0, removed=QUERY_FLAG(op,FLAG_REMOVED);
  223.   char *newpath=NULL, *lastlevel=NULL;
  224.   int oldx = (-1), oldy = (-1), last_x = op->x, last_y = op->y;
  225.  
  226.   dummy_map.pending = (objectlink *) NULL;
  227.   dummy_map.in_memory = MAP_LOADING;
  228.  
  229.   if (exit_ob) {
  230.     x=EXIT_X(exit_ob);
  231.     y=EXIT_Y(exit_ob);
  232.  
  233.     if (EXIT_PATH(exit_ob)) {
  234.       newpath = normalize_path (exit_ob->map->path, EXIT_PATH(exit_ob));
  235.     } else {
  236.       if (EXIT_LEVEL (exit_ob) > 0)
  237.         LOG(llevError,"Number Map levels are no more supported\n");
  238.     }
  239.  
  240.   } else
  241.     newpath = op->contr->maplevel;
  242.  
  243.  
  244.   /* If no map path has been found yet, just keep the player on the
  245.    * map he is on right now
  246.    */
  247.   if(!newpath)
  248.     newpath = op->map->path;
  249.  
  250.   /* See if the map actually exists */
  251.   if (!has_been_loaded(newpath) && check_path(newpath) == -1) {
  252.      sprintf(buf,"The %s is closed.", exit_ob->name);
  253.     new_draw_info(NDI_UNIQUE, 0,op, buf);
  254.     return;
  255.   }
  256.   /* Clear the player's count, and reset direction */
  257.   op->direction=0;
  258.   op->contr->count=0;
  259.   op->contr->count_left=0;
  260.  
  261.   if(exit_ob && exit_ob->stats.dam && op->type==PLAYER)
  262.        hit_player(op,exit_ob->stats.dam,exit_ob,exit_ob->attacktype);
  263.  
  264.   /* Keep track of the map the player is on right now */
  265.   m=op->map;
  266.  
  267.  
  268.   /* When logging in, the object is already removed.  If that is
  269.    * not the case, then the following is used */
  270.   if(!removed) {
  271.     remove_ob(op);
  272.  
  273.     lastlevel = m->path;
  274.  
  275.     op->map = NULL;
  276.  
  277.     if(strcmp (newpath, m->path)) {
  278.  
  279.       /* Remove any golems */
  280.       if(op->contr->golem) {
  281.         remove_friendly_object(op->contr->golem);
  282.         remove_ob(op->contr->golem);
  283.         free_object(op->contr->golem);
  284.         op->contr->golem=NULL;
  285.       }
  286.  
  287.       /* This stuff should probably be moved to ready_map: */
  288.       op->map = &dummy_map;
  289.  
  290. #if MAP_MAXTIMEOUT
  291.       m->timeout = MAP_TIMEOUT(m);
  292.       if (m->timeout > MAP_MAXTIMEOUT) {
  293.       m->timeout = MAP_MAXTIMEOUT;
  294.       }
  295.       swap_below_max (newpath);
  296.       /* Swap out the oldest map if low on mem */
  297. #else
  298.       swap_map(m);
  299. #endif
  300.  
  301.     }
  302.     m->players--;
  303.   }
  304.   /* Do any processing to get the map loaded and ready */
  305.   op->map = ready_map_name(newpath,0);
  306.  
  307. /*LOG(llevDebug, "enter_exit: %s\n", newpath); */
  308.  
  309.   if (op->map==NULL) { /* Something went wrong, try to go back */
  310.     int x2,y2;
  311.     object *enc;
  312.     LOG(llevError,"Error, couldn't open map %s.\n", newpath);
  313.     op->map = ready_map_name (lastlevel, 0);
  314.     x = last_x;
  315.     y = last_y;
  316.     oldx = op->x, oldy = op->y;
  317.     LOG(llevDebug, "Trying to remove all entries to the map.\n");
  318.     for (x2 = (-2); x2 < 3; x2++)
  319.       for (y2 = (-2); y2 < 3; y2++) {
  320.         if (out_of_map(op->map, x2 + op->x, y2 + op->y))
  321.           continue;
  322.         enc = get_map_ob(op->map, x2 + op->x, y2 + op->y);
  323.         if (!enc)
  324.           continue;
  325.         if (enc->type != ENCOUNTER || enc->slaying == NULL ||
  326.             strcmp(enc->slaying, newpath))
  327.           continue;
  328.         free_string(enc->slaying);
  329.         enc->slaying = (char *) NULL;
  330.       }
  331.   } 
  332. #if 0    /* Are these lines really needed?  What map a player is on can
  333.      * be found out with the maps command anyway.
  334.      */
  335.   else if(exit_ob!=NULL && exit_ob->name) {
  336.     new_draw_info_format(NDI_UNIQUE | NDI_ALL, 0, op,
  337.     "%s enters %s.",op->name,exit_ob->name);
  338.   } else {
  339.     new_draw_info_format(NDI_UNIQUE | NDI_ALL, 0, op,   
  340.     "%s teleports to level %s.",op->name,
  341.               op->map->map_object->name);
  342.   }
  343. #endif
  344. /*  new_draw_info(NDI_UNIQUE, 0,op, buf);*/
  345.   op->map->players++;
  346.  
  347.  
  348.   /* If objects are being updated while the map is loading, things like
  349.    * pets will be put into the players map, pending element.  That is
  350.    * really just the dummy_map.  Since the map has actually loaded now,
  351.    * we want to append that list to the 'real' loaded maps pending
  352.    * list -- MSW
  353.    */
  354.   if(dummy_map.pending != (objectlink *) NULL) {
  355.     objectlink *obl;
  356.     for(obl = op->map->pending; obl!= NULL && obl->next != NULL; 
  357.         obl=obl->next);
  358.     if(obl == NULL)
  359.       op->map->pending = dummy_map.pending;
  360.     else
  361.       obl->next = dummy_map.pending;
  362.   }
  363.  
  364.   op->contr->loading = op->map;
  365.   if (oldx != (-1)) {
  366.     op->contr->new_x = oldx;
  367.     op->contr->new_y = oldy;
  368.   } else {
  369.     op->contr->new_x = x;
  370.     op->contr->new_y = y;
  371.   }
  372.   op->contr->removed = removed;
  373.   op->map->timeout = 0;
  374.  
  375. /* I don't think, at least the way things are now, that this can ever
  376.  * happen.
  377.  */
  378.   if(op->map->in_memory == MAP_LOADING) {
  379.     LOG(llevDebug, "Players map is still loading!?\n");
  380.     return; /* This will block the player until map has been loaded */
  381.   }
  382. #ifdef USE_LIGHTING
  383.   if(op->lights||op->glow_radius>0) remove_carried_lights(op,m);
  384. #endif
  385.   enter_map(op);
  386. }
  387.  
  388. /*
  389.  *  enter_map():  handles the final stages of entering a new map.
  390.  */
  391.  
  392. void enter_map(object *op) {
  393.   op->map = op->contr->loading;
  394.   op->contr->loading = NULL;
  395.   if((op->contr->new_x || op->contr->new_y) &&
  396.      !out_of_map(op->map,op->contr->new_x,op->contr->new_y))
  397.     op->x = op->contr->new_x, op->y = op->contr->new_y;
  398.   else {
  399.     int i = find_free_spot(op->arch,op->map,
  400.                            EXIT_X(op->map->map_object),
  401.                EXIT_Y(op->map->map_object),1,9);
  402.     op->x = EXIT_X(op->map->map_object) + freearr_x[i];
  403.     op->y = EXIT_Y(op->map->map_object) + freearr_y[i];
  404.   }
  405.   if(!op->contr->removed) {
  406.     SET_FLAG(op, FLAG_NO_APPLY);
  407.     insert_ob_in_map(op,op->map);
  408.     CLEAR_FLAG(op, FLAG_NO_APPLY);
  409.   }
  410.   op->enemy = NULL;
  411. #if 0
  412.   op->contr->drawn[5][5].number = 0;
  413.   /*
  414.    * draw_colorpix routine cannot find out, if the background of player has
  415.    * changed, and would not redraw player...
  416.    */
  417. #endif
  418. #ifdef USE_LIGHTING
  419.   if(op->lights) add_carried_lights(op);
  420. #endif
  421.   enter_pending_objects(op->map);
  422. }
  423.  
  424. /*
  425.  * process_active_maps(): Works like process_events(), but it only
  426.  * processes maps which are loaded and readied.
  427.  * It will check that it isn't called too often, and abort
  428.  * if time since last call is less than MAX_TIME.
  429.  *
  430.  */
  431.  
  432. void process_active_maps() {
  433.   mapstruct *map;
  434.  
  435. #if 0
  436.   /* Even in single player mode, it is nice to still be able to do stuff
  437.    * while a map is saving.
  438.    */
  439.   if(first_player==NULL || first_player->next==NULL)
  440.     return; /* No point in the following in one-player mode */
  441. #endif
  442.  
  443. /*
  444.  * If enough time has elapsed, do some work.
  445.  */
  446.   if(enough_elapsed_time())
  447.     for(map=first_map;map!=NULL;map=map->next)
  448.       if(map->in_memory == MAP_IN_MEMORY) {
  449.         if(players_on_map(map)==0)
  450.           continue;
  451.         process_events(map);
  452.       }
  453. }
  454.  
  455. #if 0
  456. /* process_events has been extended to take a map arguement, and
  457.  * if that is non null, only process objects on that map.  As such,
  458.  * process_map is no longer needed.
  459.  */
  460. /*
  461.  * process_map(map): works like process_events(), but it only processes
  462.  * objects within the map 'map'.
  463.  */
  464.  
  465. void process_map(mapstruct *map) {
  466.   int flag;
  467.   object *op, *next;
  468.  
  469.   process_players1(map);
  470.  
  471.   for(op=objects;op!=NULL;op=next) {
  472.     if(QUERY_FLAG(op, FLAG_FREED)) { /* Was this object somehow freed as a result of */
  473.                        /* the actions of the previous object? */ 
  474.       flag=0;
  475.       break;
  476.     }
  477.     next=op->next;
  478.  
  479.     if(op->map!=map || op->type == PLAYER)
  480.       continue;
  481.  
  482.     if (op->last_anim>=op->anim_speed && op->anim_speed != 0) {
  483.       animate_object(op);
  484.       op->last_anim=1;
  485.     } else op->last_anim++; 
  486. #ifdef CASTING_TIME
  487.     if (op->casting > 0){
  488.       op->casting--;
  489.     }
  490. #endif
  491.     if(op->speed_left>0) {
  492.       --op->speed_left;
  493.       if(process_object(op))
  494.         continue;
  495.     }
  496.   }
  497. /* Now go through all objects and give them new speed */
  498.   for(op=objects;op!=NULL;op=op->next)
  499.     if(op->map==map&&op->speed&&op->speed_left<=0)
  500.       op->speed_left+=op->speed>0?op->speed:-op->speed;
  501.  
  502.   process_players2(map);
  503. }
  504. #endif
  505.  
  506. /* process_players1 and process_players2 do all the player related stuff.
  507.  * I moved it out of process events and process_map.  This was to some
  508.  * extent for debugging as well as to get a better idea of the time used
  509.  * by the various functions.  process_players1() does the processing before
  510.  * objects have been updated, procesS_players2() does the processing that
  511.  * is needed after the players have been updated.
  512.  */
  513.  
  514. void process_players1(mapstruct *map)
  515. {
  516.   int flag;
  517.   player *pl,*plnext;
  518.  
  519.   for(flag=1;flag!=0;) {
  520.     flag=0;
  521.     for(pl=first_player;pl!=NULL;pl=plnext) {
  522.  
  523.  
  524.       plnext=pl->next; /* In case a player exits the game in handle_player() */
  525.       if (map!=NULL && (pl->ob == NULL || pl->ob->map!=map)) continue;
  526.  
  527. #ifdef AUTOSAVE
  528.       /* check for ST_PLAYING state so that we don't try to save off when
  529.        * the player is logging in.
  530.        */
  531.       if ((pl->last_save_tick+AUTOSAVE)<pticks && pl->state==ST_PLAYING) {
  532.     save_player(pl->ob,1);
  533.     pl->last_save_tick = pticks;
  534.       }
  535. #endif
  536.       if(pl->ob->speed_left>0) {
  537.       if (pl->eric_server>0) {
  538.         if (handle_newcs_player(pl->ob))
  539.             flag=1;
  540.       }
  541.       else {
  542.         if(--(pl->ob->speed_left)>0) /* Another loop needed */
  543.         flag=1;
  544.         handle_player(pl->ob);
  545.       }
  546.       }
  547.     }
  548.   }
  549.   for(pl=first_player;pl!=NULL;pl=pl->next) {
  550.     if (map!=NULL && (pl->ob == NULL || pl->ob->map!=map)) continue;
  551. #ifdef CASTING_TIME
  552.     if (pl->ob->casting > 0){
  553.       pl->ob->casting--;
  554.       pl->ob->start_holding = 1;
  555.     }
  556.     /* set spell_state so we can update the range in stats field */ 
  557.     if ((pl->ob->casting == 0) && (pl->ob->start_holding ==1)){
  558.       pl->ob->start_holding = 0;
  559.       pl->ob->spell_state = 1;
  560.     }
  561. #endif
  562.     do_some_living(pl->ob);
  563.     draw(pl->ob);
  564.   }
  565. }
  566.  
  567. void process_players2(mapstruct *map)
  568. {
  569.   player *pl;
  570.  
  571. /* Then check if any players should use weapon-speed instead of speed */
  572.   for(pl=first_player;pl!=NULL;pl=pl->next) {
  573.     if (map!=NULL) {
  574.       if(pl->ob == NULL || QUERY_FLAG(pl->ob,FLAG_REMOVED))
  575.         continue;
  576.       else if(pl->loading != NULL) /* Player is blocked */
  577.         pl->ob->speed_left -= pl->ob->speed;
  578.       if (pl->ob->map!=map) continue;
  579.     }
  580.  
  581. #ifdef SOUND_EFFECTS
  582.     if (pl->play_count > 0)
  583.       pl->play_count--;
  584. #endif
  585.     if(pl->has_hit) {
  586.       float hit_speed = pl->ob->speed/pl->weapon_sp - pl->ob->speed;
  587.  
  588.       if (hit_speed<pl->ob->speed) hit_speed = pl->ob->speed;
  589.  
  590.       pl->ob->speed_left+=hit_speed;
  591.       /* This could happen if the player still has left over speed */
  592.       if (pl->ob->speed_left>hit_speed) pl->ob->speed_left=hit_speed;
  593.     }
  594.     else if (pl->ob->speed_left>pl->ob->speed)
  595.     pl->ob->speed_left = pl->ob->speed;
  596.   }
  597.  
  598. /* Then synchronize the different screens to avoid jerky movement */
  599.   for(pl=first_player;pl!=NULL;pl=pl->next) {
  600.     if (pl->eric_server > 0) {
  601.       esrv_bar(pl->eric_server,"sync");
  602.       continue;
  603.     }
  604.     if (pl->sync && ++pl->cur_sync >= pl->sync) {
  605.       XSync(pl->gdisp,False);
  606.       pl->cur_sync = 0;
  607.     }
  608.     else
  609.       XFlush(pl->gdisp);
  610.   }
  611. }
  612.  
  613. #define SPEED_DEBUG
  614. #define NEW_PROCESS_EVENTS
  615. /*
  616.  * Withe NEW_PROCESS_EVENTS, this function no longer hogs as much
  617.  * cpu time as it did.
  618.  * Extended to take a map arguement.  This way, process_map is no
  619.  * longer needed.
  620.  */
  621.  
  622.  
  623. void process_events(mapstruct *map) {
  624.   object *op, *next;
  625.  
  626.  process_players1(map);
  627.  
  628. #ifdef NEW_PROCESS_EVENTS
  629.  for (op=active_objects; op!=NULL; op=next) {
  630. #else
  631.  for(op=objects;op!=NULL;op=next) {
  632. #endif
  633.     if(QUERY_FLAG(op, FLAG_FREED)) { /* Was this object somehow freed as a result of */
  634.                        /* the actions of the previous object? */ 
  635.       LOG(llevDebug,"Free object on list, process_events\n");
  636. /*      break;*/
  637.     }
  638.  
  639. #ifdef NEW_PROCESS_EVENTS
  640.     next=op->active_next;
  641. #else
  642.     next=op->next;
  643. #endif
  644.  
  645.     if (op->map == NULL && op->env == NULL && op->name &&
  646.         op->type!=MAP && map==NULL)
  647.     {
  648.       LOG(llevError, "Object without map or inventory: %s (%d)\n",
  649.               op->name, op->count);
  650.       continue;
  651.     }
  652.  
  653.     if (map!=NULL && op->map!=map)
  654.     continue;
  655.  
  656.     if(!op->speed) {
  657. #ifdef NEW_PROCESS_EVENTS
  658.       /* This is not a real problem, unless it repeats for the the same
  659.        * object.  IF it just gets printed once, it likely means that that
  660.        * object was killed/changed by the previous object
  661.        */
  662.       LOG(llevDebug, "Object %s has no speed, but is on active list\n",
  663.     op->arch->name);
  664. #endif
  665.       continue;
  666.     }
  667. #if defined(SPEED_DEBUG) && !defined(NEW_PROCESS_EVENTS)
  668.     if (op->active_prev==NULL && op->active_next==NULL)
  669.     LOG(llevDebug, "Object %s has speed, but not on active list\n", op->arch->name);
  670. #endif
  671.  
  672. /* Eneq(@csd.uu.se): Handle archetype-field anim_speed differently when
  673.    it comes to the animation. If we have a value on this we don't animate it
  674.    at speed-events. */
  675.  
  676.     if (op->anim_speed && op->last_anim>=op->anim_speed) {
  677.       animate_object(op);
  678.       op->last_anim=1;
  679.     } else op->last_anim++; 
  680.  
  681.     if(op->speed_left>0) {
  682.       --op->speed_left;
  683.       process_object(op);
  684.     }
  685. #ifdef CASTING_TIME
  686.     if (op->casting > 0)
  687.       op->casting--;
  688. #endif
  689.     if (op->speed_left <= 0)
  690.     op->speed_left+=(op->speed>0?op->speed:-op->speed);
  691.   }
  692.  
  693.   process_players2(map);
  694. }
  695.  
  696. void clean_tmp_files() {
  697.   mapstruct *m;
  698.   player *pl;
  699.  
  700.   LOG(llevError,"Cleaning up...\n");
  701.   for(pl=first_player;pl!=NULL;pl=pl->next)
  702.     remove_lock(pl);
  703.   for(m=first_map;m!=NULL;m=m->next)
  704.     clean_tmp_map(m);
  705. #if defined(UNIQUE_ITEMS) && defined(LOCK_ITEMS)
  706.   clean_lockfiles();
  707. #endif
  708. }
  709.  
  710. void leave(player *pl) {
  711.   char buf[MAX_BUF];
  712.  
  713.   /* Lets free this before you close the connection */
  714.   if (pl->pixmaps) free_pixmaps(pl->gdisp, pl->pixmaps);
  715.   if (pl->masks) free_pixmaps(pl->gdisp, pl->masks);
  716.  
  717.  
  718.   if (pl->eric_server > 0)
  719.     esrv_remove_player(pl->eric_server);
  720.   else {
  721.     XSync(pl->gdisp, False);
  722.     /* Free all the GCs we made */
  723.     if(pl->gc_root)
  724.       XFreeGC(pl->gdisp, pl->gc_root);
  725.     if(pl->gc_game)
  726.       XFreeGC(pl->gdisp, pl->gc_game);
  727.     if(pl->gc_stats)
  728.       XFreeGC(pl->gdisp, pl->gc_stats);
  729.     if(pl->gc_info)
  730.       XFreeGC(pl->gdisp, pl->gc_info);
  731.     if(pl->gc_inv_text)
  732.       XFreeGC(pl->gdisp, pl->gc_inv_text);
  733.     if(pl->gc_inv_icon)
  734.       XFreeGC(pl->gdisp, pl->gc_inv_icon);
  735.     if(pl->gc_look_text)
  736.       XFreeGC(pl->gdisp, pl->gc_look_text);
  737.     if(pl->gc_look_icon)
  738.       XFreeGC(pl->gdisp, pl->gc_look_icon);
  739.     if(pl->gc_message)
  740.       XFreeGC(pl->gdisp, pl->gc_message);
  741.     if(pl->gc_xpm_floor)
  742.       XFreeGC(pl->gdisp, pl->gc_xpm_floor);
  743.     if(pl->gc_xpm_object)
  744.       XFreeGC(pl->gdisp, pl->gc_xpm_object);
  745.     XDestroyWindow(pl->gdisp,pl->win_game);
  746.     XCloseDisplay(pl->gdisp);
  747.   }
  748.  
  749.   (void) sprintf(buf,"%s left the game.",pl->name);
  750.   if (pl->ob->map->in_memory==MAP_IN_MEMORY)
  751.     pl->ob->map->timeout = MAP_TIMEOUT(pl->ob->map);
  752.   pl->ob->map->players--;
  753.   pl->ob->map=NULL;
  754.   pl->ob->type = DEAD_OBJECT; /* To avoid problems with inventory window */
  755.   free_player(pl);
  756. #ifdef SERVER
  757.   if(server_mode != SERVER_ENABLED)
  758. #endif
  759.   if(first_player==NULL) { /* Last player left the game */
  760.     clean_tmp_files();
  761.     exit(0);
  762.   }
  763.   new_draw_info(NDI_UNIQUE | NDI_ALL, 5, NULL, buf);
  764. }
  765.  
  766. int forbid_play()
  767. {
  768. #if !defined(_IBMR2) && !defined(___IBMR2) && defined(PERM_FILE)
  769.     char buf[MAX_BUF], day[MAX_BUF];
  770.     FILE *fp;
  771.     time_t clock;
  772.     struct tm *tm;
  773.     int i, start, stop, forbit=0, comp;
  774.  
  775.     clock = time (NULL);
  776.     tm = (struct tm *) localtime (&clock);
  777.  
  778.     sprintf (buf, "%s/%s", LibDir, PERM_FILE);
  779.     if ((fp = open_and_uncompress(buf, 0, &comp)) == NULL)
  780.     return 0;
  781.  
  782.     while (fgets (buf, MAX_BUF, fp)) {
  783.     if (!strncmp (buf, "msg", 3)) {
  784.         if (forbit)
  785.         while (fgets (buf, MAX_BUF, fp))  /* print message */
  786.             fputs (buf, logfile);
  787.         break;
  788.  
  789.     } else if (sscanf (buf, "%s %d%*c%d\n", day, &start, &stop) != 3) {
  790.         LOG(llevDebug, "Warning: Incomplete line in permission file ignored.\n");
  791.         continue;
  792.     }
  793.  
  794.     for (i=0; i< 7; i++) {
  795.         if (!strncmp (buf, days[i], 3) && (tm->tm_wday == i) && 
  796.         (tm->tm_hour >= start) && (tm->tm_hour < stop))
  797.         forbit = 1;
  798.     }
  799.     }
  800.  
  801.     close_and_delete(fp, comp);
  802.  
  803.     return forbit;
  804. #else
  805.     return 0;
  806. #endif
  807. }
  808.  
  809. /*
  810.  *  do_specials() is a collection of functions to call from time to time.
  811.  */
  812.  
  813.  
  814. void do_specials() {
  815.   static int special_count = 0, special2 = 0;
  816.  
  817.   if(++special_count < 500)
  818.     return;
  819.   special_count = 0;
  820.   special2++;
  821.   flush_old_maps();    /* Clears the tmp-files of maps which have reset */
  822. #if 0
  823. #ifdef DEBUG_MALLOC_LEVEL
  824.   if (!malloc_verify())
  825.     LOG(llevError,"Warning - heap is corrupted\n");
  826.   else
  827.     LOG(llevDebug,"Heap checks out OK.\n");
  828. #endif
  829. #endif
  830.   if(!(special2%5)) {
  831.     fix_weight();        /* Hack to fix weightproblems caused by bugs */
  832.     if (!(special2%25))
  833.       fix_luck();
  834.   }
  835. }
  836.  
  837. /*
  838.  * last_time is when the last tick was executed.
  839.  * We don't need to know the timezone since we're only interested in
  840.  * the delta time since the last 'tick' .
  841.  */
  842. struct timeval last_time;
  843. struct timezone dummy_timezone;
  844.  
  845. int main(int argc,char **argv,char **env) {
  846.  
  847.  /*
  848.   * Set up some global pointers, to make things easy:
  849.   */
  850.   gargc=argc, gargv=argv, genv=env;
  851.  
  852. #ifdef DEBUG_MALLOC_LEVEL
  853.   malloc_debug(DEBUG_MALLOC_LEVEL);
  854. #endif
  855.  
  856.   init();
  857.  
  858.   for(;;) {
  859.     nroferrors = 0;
  860. #ifdef LONGJUMP
  861.     setjmp(jump_addr);
  862. #endif
  863.  
  864.     check_socket();      /* Check for new connections/data */
  865.     doeric_server();
  866.     process_events(NULL);    /* "do" something with objects with speed */
  867.     check_active_maps(); /* Removes unused maps after a certain timeout */
  868.     do_specials();       /* Routines called from time to time. */
  869.  
  870.     sleep_delta();
  871.   }
  872. }
  873.